#ifndef SATURNOS_INC_KERN_PROC_H
#define SATURNOS_INC_KERN_PROC_H

#include <types.h>
#include <trap.h>
#include <kern/mmu.h>
#include <kern/memlayout.h>
#include <kern/spinlock.h>
#include <pool.h>

typedef uint32_t pid_t;

#define NRPROCS		1024
#define PROCX(pid)	((pid) & 0x3FF)

enum proc_state_t {
	PROC_FREE = 0,
	PROC_EMBRYO,
	PROC_RUNNABLE,
	PROC_RUNNING,
	PROC_SLEEPING,
	PROC_IPC_RECV,
	PROC_IPC_SEND,
	PROC_ZOMBIE
};

struct context_t {
	uint32_t edi;
	uint32_t esi;
	uint32_t ebx;
	uint32_t ebp;
	uint32_t eip;
};

struct proc_t {
	// proc module
	pid_t id;			// proc id, use PROCX to get index
	pid_t parent_id;		// parant proc id
	int nr_child_procs;		// number of child procs
	enum proc_state_t state;	// current proc state
	struct trapframe_t* tf;		// pointer to trapframe

	// sched module
	struct context_t* kctx;	// saved kernel state
	
	struct link_t link;		// use link to add/pop to pools

	// vm module
	struct spinlock_t memlock;	// used for locking proc memory
	physaddr_t kstack_pa;		// physical address of the kernel stack
	void* kstack;			// pointer to kernel stacktop
	pde_t* pgdir;			// pointer to page dir
};

struct cpu_t {
	uint8_t id;
	volatile int booted;		// has the cpu started

	// proc module
	struct proc_t* currproc;

	// sched module
	struct context_t* schedctx;	// schedulder mini proc context
	int ncli;			// number of recursive pushcli
	int interrupt_enabled;		// interrup enabled status (for popcli)

	// vm module
	struct taskstate_t ts;		// Used by x86 to find stack for interrupt
	struct segdesc gdt[NSEGS];	// x86 global descriptor table

	// shared
	struct cpu_t* cpu;
};

struct cpu_t* cpus;
int ncpus;

extern struct cpu_t* cpu __asm("%gs:0");

// TODO change this function place to mp.h
int cpunum(void);

/** 
* array of all procs in the system, initiated in vm module.
* page_pgdir member is preallocated and contains the correct value.
*/
struct proc_t* procs;

/**
* initiate free proc and scheduler
*/
void proc_init(void);

/**
* allocates a new proc and a kernel stack for it,
* pgdir is not initiated and state is embryo
*
* @param p_proc - output: will contain the proc that was allocated
* @param parent - intput: the parent proc id
*
* @return 0 for success
*         -ENOPROC if there were no free procs
*         -ENOMEM if stack or pgdir allocation failed
*/
int proc_alloc(struct proc_t** p_proc, pid_t parent);

/*
* free a proc
*/
int proc_free(struct proc_t* proc);

/**
* loader in kernel space. Used for loading staticly binded binaries
* during start up (such as the first proc, init)
*/
void proc_load_code(struct proc_t* proc, uint8_t* binary, int sz);


#endif /* SATURNOS_INC_KERN_PROC_H */

